﻿using MongoDB.Driver;
using SimpleInjector;
using Sustainalytics.Claims;
using Sustainalytics.ClientDW.DataAccessLayer;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.Companies;
using Sustainalytics.Controversies.BusinessLogic;
using Sustainalytics.DataLayer;
using Sustainalytics.DataLayer.EsgRatings;
using Sustainalytics.DataLayer.PI;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.Entities.ProductInvolvement;
using Sustainalytics.Entities.SustainableProducts;
using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.Portfolios.BL;
using Sustainalytics.ProductInvolvement.BL;
using Sustainalytics.Replication.Publisher;
using Sustainalytics.ScreeningTool.BL;
using Sustainalytics.Universes.BusinessLogic;
using System.Collections.Generic;
using System.Configuration.Abstractions;
using System.Web.Http;

namespace Sustainalytics.ScreeningTool.Service
{
    public static class CompositionRoot
    {
        private static readonly Dictionary<string, string> serviceBusParams = new Dictionary<string, string>
                {
                        { "ConnectionString", ConfigurationManager.Instance.AppSettings["Microsoft.ServiceBus.ConnectionString"] },
                        { "RegionEndpoint", ConfigurationManager.Instance.AppSettings["Microsoft.ServiceBus.RegionEndpoint"] },
                        { "SessionId", ConfigurationManager.Instance.AppSettings["Microsoft.ServiceBus.SessionId"] },
                        { "TopicPath", ConfigurationManager.Instance.AppSettings["Microsoft.ServiceBus.TopicPath"] },
                };
        private static string _clientPlatformConnectionString;

        public static Container RegisterDependencies(HttpConfiguration config)
        {
            var container = new Container();

            container.Options.DefaultScopedLifestyle = new SimpleInjector.Lifestyles.AsyncScopedLifestyle();
            container.RegisterWebApiControllers(config);

            _clientPlatformConnectionString = ConfigurationManager.Instance.ConnectionStrings["ClientPlatform"].ConnectionString;

            container.RegisterMisc(serviceBusParams);

            container.RegisterCollections();

            container.RegisterRepositories();

            container.RegisterBussinessLogic();

            container.RegisterPropertyDependency();

            container.Verify();
            return container;
        }

        private static void RegisterCollections(this Container container)
        {
            container.Register(() => MongoFactory.GetCollectionFromDatabase<CorporateData>(MongoFactory.GetConnectionStrings().ClientDW));
            container.Register(() => MongoFactory.GetCollectionFromDatabase<SustainableProductsFramework>(MongoFactory.GetConnectionStrings().ProductInvolvementDW));
            container.Register(() => MongoFactory.GetCollectionFromDatabase<ProductInvolvementFramework>(MongoFactory.GetConnectionStrings().ProductInvolvementDW));

            container.Register(typeof(IRepositoryCollection<CorporateData>), () => new RepositoryCollection<CorporateData>(MongoFactory.GetConnectionStrings().ClientDW));
            container.Register(typeof(IRepositoryCollection<Filter>), () => new RepositoryCollection<Filter>(_clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<CorporateDataBasic>), () => new RepositoryCollection<CorporateDataBasic>(MongoFactory.GetConnectionStrings().ClientDW, "CorporateData"));
            container.Register(typeof(IRepositoryCollection<UserFilterSettings>), () => new RepositoryCollection<UserFilterSettings>(_clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<GovernanceIndicatorTemplate>), () => 
                new RepositoryCollection<GovernanceIndicatorTemplate>(MongoFactory.GetConnectionStrings().GovernanceDW));
            container.Register(typeof(IRepositoryCollection<Portfolio>), () => new RepositoryCollection<Portfolio>(_clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<PortfolioDetails>), () => new RepositoryCollection<PortfolioDetails>(_clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<PortfolioMatches>), () => new RepositoryCollection<PortfolioMatches>(_clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<PortfolioUserInput>), () => new RepositoryCollection<PortfolioUserInput>(_clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<EsgInputFile>), () => new RepositoryCollection<EsgInputFile>(_clientPlatformConnectionString));
            container.Register(typeof(IRepositoryCollection<ProductInvolvementData>), () => new RepositoryCollection<ProductInvolvementData>(MongoFactory.GetConnectionStrings().ProductInvolvementDW));
        }

        private static void RegisterRepositories(this Container container)
        {
            container.Register(typeof(IAccountsRepository), () => AccountsRepository.GetAccountsRepository(_clientPlatformConnectionString));
            container.Register(typeof(ICompanyScreeningRepository), () => CompanyScreeningRepository.GetCompanyScreeningRepository(_clientPlatformConnectionString));
            container.Register(typeof(IClientDwRepository), () => ClientDwRepository.GetInstance(MongoFactory.GetConnectionStrings().ClientDW));
            container.Register(typeof(IUniversesRepository), () => UniversesRepository.GetUniversesRepository(MongoFactory.GetConnectionStrings().ClientUniverses));
            container.Register(typeof(IUniversesManagement), () => UniversesManagement.GetInstance(UniversesRepository.GetUniversesRepository(MongoFactory.GetConnectionStrings().ClientUniverses)));
            container.Register(typeof(IScreeningDataRepository), () => ScreeningDataRepository.GetScreeningDataRepository(MongoFactory.GetConnectionStrings().ScreeningDW));
            container.Register(typeof(IFilterCriteriaRepository), () => new FilterCriteriaRepository(_clientPlatformConnectionString));
            container.Register(typeof(IFiltersRepository), () => new FiltersRepository(_clientPlatformConnectionString));
            container.Register(typeof(IProductInvolvementFrameworkRepository), () => new ProductInvolvementFrameworkRepository(MongoFactory.GetConnectionStrings().ProductInvolvementDW));
            container.Register(typeof(IProductInvolvementDataRepository), () => new ProductInvolvementDataRepository(MongoFactory.GetConnectionStrings().ProductInvolvementDW, MongoFactory.GetConnectionStrings().ClientDW));
            container.Register(typeof(IFileRepository), () => new FileRepository(_clientPlatformConnectionString));
        }

        private static void RegisterPropertyDependency(this Container container)
        {
            container.RegisterInitializer<ICustomPortfolioUpdateHandler>(
                handler =>
                {
                    handler.SetPortfolioMatching(container.GetInstance<PortfolioMatching>());
                    handler.SetScreeningToolFilterManagement(container.GetInstance<ScreeningToolFilterManager>());
                });
        }

        private static void RegisterBussinessLogic(this Container container)
        {
            container.Register((typeof(ICompanyMatchingLogic)), () => new CompanyMatchingLogic(container.GetInstance<IMongoCollection<CorporateData>>()));

            container.Register(() => EsgInputFileRepository.GetInstance(
                    container.GetInstance<IFileRepository>(),
                    container.GetInstance<IRepositoryCollection<EsgInputFile>>()
                ));

            container.Register(() => new CustomPortfolioUpdateHandler(

                container.GetInstance<IRepositoryCollection<Portfolio>>(),
                container.GetInstance<IRepositoryCollection<PortfolioDetails>>(),
                container.GetInstance<IRepositoryCollection<PortfolioMatches>>(),
                container.GetInstance<IRepositoryCollection<PortfolioUserInput>>(),
                container.GetInstance<IEsgInputFileRepository>(),
                container.GetInstance<ServiceBusPublisher>(),
                container.GetInstance<ICompanyMatchingLogic>()));

            container.Register(() => new ScreeningToolFilterManager(container.GetInstance<IRepositoryCollection<Filter>>()));
            container.Register(() => new CorporateDataUniversesLoader(container.GetInstance<IMongoCollection<CorporateData>>()));
            container.Register(() => new PortfolioMatching(
                container.GetInstance<ICompanyMatchingLogic>(),
                container.GetInstance<CorporateDataUniversesLoader>()));

            container.Register(() => MongoFactory.GetCollectionFromDatabase<ResultOutput>(_clientPlatformConnectionString));
            container.Register(() => new PortfolioTypeCollection<Portfolio>(
                new RepositoryCollection<Portfolio>(_clientPlatformConnectionString),
                new RepositoryCollection<Portfolio>(MongoFactory.GetConnectionStrings().ClientDW)));
            container.Register(() => new PortfolioTypeCollection<PortfolioDetails>(
                new RepositoryCollection<PortfolioDetails>(_clientPlatformConnectionString),
                new RepositoryCollection<PortfolioDetails>(MongoFactory.GetConnectionStrings().ClientDW)));

            container.Register(typeof(IPortfolioReadHandler), () => new PortfolioReadHandler(
                    container.GetInstance<PortfolioTypeCollection<Portfolio>>(),
                    container.GetInstance<PortfolioTypeCollection<PortfolioDetails>>(),
                    container.GetInstance<IRepositoryCollection<CorporateDataBasic>>()));

            container.Register(typeof(ICompanyScreening), typeof(CompanyScreening));

            container.Register(typeof(IFilterManager), () => new FilterManager(
                container.GetInstance<IAccountsRepository>(),
                container.GetInstance<ICompanyScreeningRepository>(),
                container.GetInstance<IFiltersRepository>(),
                container.GetInstance<IFilterCriteriaRepository>(),
                container.GetInstance<IRepositoryCollection<UserFilterSettings>>(),
                container.GetInstance<IClientDwRepository>(),
                container.GetInstance<ServiceBusPublisher>()));

            container.Register(() => FilterCriteriaManager.GetInstance(
                container.GetInstance<ICompanyScreeningRepository>(),
                container.GetInstance<IClientDwRepository>(),
                container.GetInstance<IFilterCriteriaRepository>(),
                container.GetInstance<ServiceBusPublisher>()));

            container.Register(typeof(IProductInvolvementBussinesLogic), () =>
                ProductInvolvementBussinesLogic.CreateProductInvolvementBussinesLogic(
                container.GetInstance<IFileRepository>(),
                container.GetInstance<IProductInvolvementDataRepository>(),
                container.GetInstance<IClientDwRepository>(),
                container.GetInstance<IProductInvolvementFrameworkRepository>(),
                container.GetInstance<ICompanyScreeningRepository>(),
                container.GetInstance<ProductInvolvementSerilog>(),
                container.GetInstance<IMongoCollection<CorporateData>>(),
                container.GetInstance<IRepositoryCollection<CorporateData>>(),
                container.GetInstance<IRepositoryCollection<ProductInvolvementData>>()));
        }

        private static void RegisterMisc(
            this Container container,
            Dictionary<string, string> serviceBusParams)
        {
            container.Register(() => MongoFactory.GetConnectionStrings());
            container.RegisterSingleton(typeof(IClaimsChecker), () => new ClaimsChecker());
            container.RegisterSingleton(() => { return new ServiceBusPublisher(serviceBusParams); });
            container.RegisterSingleton(typeof(ProductInvolvementSerilog), () => ProductInvolvementSerilog.Log);
        }
    }
}